﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cz.muni.fi.pb138.QueryService;
using System.Xml.Linq;
using System.Windows.Forms;

namespace cz.muni.fi.pb138.Sessions
{
	/// <summary>
	/// Opens a session with the db at the instantiation.
	/// The class provides all the necessary functionality to handle the database queries
	/// </summary>
	/// <remarks>
	/// The connection needs to be closed manually by calling a <c>Dispose()</c> method
	/// </remarks>
    public class QuerySession : IDisposable
    {
        QueryClient query = new QueryClient();
        string sessionQueryId;
        public QuerySession()
        {
            query.Open();
            sessionQueryId = query.connect("admin", "testxml");
        }

        /// <summary>
        /// Retrieves all media from a database
        /// </summary>
        /// <returns><c>IList</c> of <c>Media</c> classes with all the media corresponding to the ones in a database</returns>
        public IList<Media> GetAllMedias()
        {
            QueryResponse res = query.xquery(sessionQueryId, Encoding.UTF8.GetBytes("doc(\"" + MediaManager.Login + "\")/medias/medium"));
            string[] records = new string[0];
            if (res.hits > 0)
                records = query.retrieve(sessionQueryId, 1, res.hits, true, true, "");

            List<Media> medias = new List<Media>();

            foreach (var record in records)
            {
                medias.Add(XElement.Parse(record));
            }

            return medias;
        }

        /// <summary>
        /// retrieves all the media, where original name contains a given phrase
        /// </summary>
        /// <param name="mediaName">a phrase that is searched for in the media's original name</param>
        /// <returns>list of all media, that contain the given phrase</returns>
        public IList<Media> GetMediaByName(string mediaName)
        {
            if (mediaName == null)
                throw new ArgumentNullException("media name is null");

            QueryResponse res = query.xquery(sessionQueryId, Encoding.UTF8.GetBytes(string.Format("doc(\"" + MediaManager.Login + "\")/medias/medium[matches(originalName,\"{0}\")]", mediaName)));

            string[] records = new string[0];
            if (res.hits > 0)
                records = query.retrieve(sessionQueryId, 1, res.hits, true, true, "");

            List<Media> medias = new List<Media>();

            foreach (var record in records)
            {
                medias.Add(XElement.Parse(record));
            }

            return medias;
        }

		/// <summary>
		/// Retrieves the media that has an ID element with the value <c>id</c> passed as argument
		/// </summary>
		/// <param name="id">the id of a media that is to be retrieved from a database</param>
		/// <returns>a <c>Media</c> class with the medium that has a given id or null if such medium does not exist</returns>
        public Media GetMediaById(long id)
        {

            QueryResponse res = query.xquery(sessionQueryId, Encoding.UTF8.GetBytes(string.Format("doc(\"" + MediaManager.Login + "\")/medias/medium[id={0}]", id)));
            string[] records = new string[0];
            if (res.hits > 0)
                records = query.retrieve(sessionQueryId, 1, res.hits, true, true, "");


            foreach (var record in records)
            {
                return XElement.Parse(record);
            }

            return null;
        }

		/// <summary>
		/// Authenticates the user and its password
		/// </summary>
		/// <param name="login">the user's unique login</param>
		/// <param name="password">a password corresponding to the given user</param>
		/// <returns>true if the <c>password</c> corresponds to an existing <c>login</c> in the database;
		///	false if login does not exist or the password is incorrect</returns>
        public bool AuthenticateUser(string login, string password)
        {

            QueryResponse res = query.xquery(sessionQueryId, Encoding.UTF8.GetBytes(string.Format("doc(\"users\")/users/user[login=\"{0}\"]", login)));
            string[] records = new string[0];
            if (res.hits > 0)
                records = query.retrieve(sessionQueryId, 1, res.hits, true, true, "");


            foreach (var record in records)
            {
                if (((String)(XElement.Parse(record).Element("password")) == password))
                    return true;
            }

            return false;
        }

		/// <summary>
		/// Tests whether a given login exists in the database.
		/// </summary>
		/// <param name="login">login that is to be checked</param>
		/// <returns>true if the login exists; false if not</returns>
        public bool UserExists(string login)
        {

            QueryResponse res = query.xquery(sessionQueryId, Encoding.UTF8.GetBytes(string.Format("doc(\"users\")/users/user[login=\"{0}\"]", login)));
            if (res.hits > 0)
            {
                MessageBox.Show("User with this user name already exists!");
                return true;
            }

            return false;
        }

		/// <summary>
		/// closes the connection properly
		/// </summary>
        public void Dispose()
        {
            try
            {
                query.disconnect(sessionQueryId);
                query.Close();
            }
            catch { }
        }

    }
}
